package deque

import (
	"sync"
)

type Deque struct {
	d []interface{}
	l int
	c int
	m *sync.RWMutex
}

func NewDeque(n int) *Deque {
	if n < 0 {
		n = 0
	}
	return &Deque{
		d: make([]interface{}, 0, n),
		l: 0,
		c: n,
		m: new(sync.RWMutex),
	}
}

func (d *Deque) Cap() int {
	return d.c
}

func (d *Deque) Len() int {
	d.m.RLock()
	defer d.m.RUnlock()
	return d.l
}

func (d *Deque) LenUnsafe() int {
	return d.l
}

func (d *Deque) PushBack(val interface{}) {
	d.m.Lock()
	defer d.m.Unlock()
	if d.c == 0 {
		d.d = append(d.d, val)
		d.l++
	} else {
		if d.l < d.c {
			d.d = append(d.d, val)
			d.l++
		} else {
			copy(d.d, d.d[1:])
			d.d[d.l-1] = val
		}
	}
}

func (d *Deque) PushBackUnsafe(val interface{}) {
	if d.c == 0 {
		d.d = append(d.d, val)
		d.l++
	} else {
		if d.l < d.c {
			d.d = append(d.d, val)
			d.l++
		} else {
			copy(d.d, d.d[1:])
			d.d[d.l-1] = val
		}
	}
}

func (d *Deque) Get(idx int) interface{} {
	d.m.RLock()
	defer d.m.RUnlock()
	return d.d[idx]
}

func (d *Deque) GetUnsafe(idx int) interface{} {
	return d.d[idx]
}

func (d *Deque) PopFront() interface{} {
	d.m.Lock()
	defer d.m.Unlock()
	if d.l == 0 {
		return nil
	}
	val := d.d[0]
	copy(d.d, d.d[1:])
	d.l--
	d.d = d.d[:d.l]
	return val
}

func (d *Deque) PopFrontUnsafe() interface{} {
	if d.l == 0 {
		return nil
	}
	val := d.d[0]
	copy(d.d, d.d[1:])
	d.l--
	d.d = d.d[:d.l]
	return val
}

func (d *Deque) PushFront(val interface{}) {
	d.m.Lock()
	defer d.m.Unlock()
	if d.l == 0 {
		d.PushBack(val)
		return
	}
	if d.c == 0 {
		d.d = append([]interface{}{val}, d.d)
		d.l++
	} else {
		d.d = append([]interface{}{val}, d.d[:d.l-1])
	}
	return
}

func (d *Deque) PushFrontUnsafe(val interface{}) {
	if d.l == 0 {
		d.PushBack(val)
		return
	}
	if d.c == 0 {
		d.d = append([]interface{}{val}, d.d)
		d.l++
	} else {
		d.d = append([]interface{}{val}, d.d[:d.l-1])
	}
	return
}

func (d *Deque) PopBack() interface{} {
	d.m.Lock()
	defer d.m.Unlock()
	if d.l == 0 {
		return nil
	}
	d.l--
	val := d.d[d.l]
	d.d = d.d[:d.l]
	return val
}

func (d *Deque) PopBackUnsafe() interface{} {
	if d.l == 0 {
		return nil
	}
	d.l--
	val := d.d[d.l]
	d.d = d.d[:d.l]
	return val
}
